﻿/*
    File name:          TechProgramViewModel
    File type:          Class
    Author:             Mads Skipper Pedersen 07299
    Creation date:      12-04-2011
    Last modified:      18-05-2011
    Last modified by:   Mads Skipper Pedersen 07299
    Description:        The ViewModel for the programmer tab
                        Here new scripts can be written and debugged
                        If a script is executed it is sent as a message to
                        the standard opperator window to be started.
                        Only visible to users with at least technician rights.
*/

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Input;
using System.Windows.Media;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using i4pro_gruppe_d.Database;
using i4pro_gruppe_d.DomainSpecificLanguage;
using i4pro_gruppe_d.Types;

namespace TechProgram.ViewModel
{
    public class TechProgramViewModel : ViewModelBase
    {
        #region Members
        private readonly AbstractDatabase db;
        private BackgroundWorker bgw;
        private Messenger MessengerInstance;
        private bool variableExceptionThrown = false;
        #endregion
        #region Propertys

        public ObservableCollection<String> ScriptList {get; set; }

        public ObservableCollection<String> DebugMessages
        {
            get;
            set;
        }

        private String codeLines;
        public String CodeLines
        {
            get
            {
                return codeLines;
            }
            set
            {
                codeLines = value;
                RaisePropertyChanged("CodeLines");
                CommandManager.InvalidateRequerySuggested();

            }
        }

        private String selectedScript;
        public String SelectedScript
        {
            get
            {
                return selectedScript;
            }
            set
            {
                selectedScript = value;
                RaisePropertyChanged("SelectedScript");
                LoadScriptExecute();
            }
        }

        private SolidColorBrush statusEllipseColor;
        public SolidColorBrush StatusEllipseColor
        {
            get
            {
                return statusEllipseColor;
            }
            set
            {
                statusEllipseColor = value;
                RaisePropertyChanged("StatusEllipseColor");
            }
        }

        private string scriptName;
        public String ScriptName
        {
            get
            {
                return scriptName;
            }
            set
            {
                scriptName = value;
                RaisePropertyChanged("ScriptName");
            }
        }
        #endregion
        #region Constructor
        public TechProgramViewModel()
        {
            ScriptList = new ObservableCollection<string>();
            DebugMessages = new ObservableCollection<string>();

            db = AbstractDatabase.Instance;

            MessengerInstance = Messenger.Default;
            
            RefreshScriptListExecute();
        }
        #endregion
        #region Commands
        #region Refresh ScriptList Command
        /// <summary>
        /// Runs RefreshScriptListExecute() when the refresh scriptlist image is pressed.
        /// </summary>
        public ICommand RefreshScriptList_Cmd
        {
            get { return new RelayCommand(RefreshScriptListExecute); }
        }
        private void RefreshScriptListExecute()
        {
            bgw = new BackgroundWorker();
            bgw.DoWork += Bgw_GetScriptList_DoWork;
            bgw.RunWorkerCompleted += Bgw_GetScriptList_Complete;

            bgw.RunWorkerAsync();
        }
        #endregion

        #region ScriptList Changed Command
        public ICommand ScriptListChanged_Cmd
        {
            get { return new RelayCommand(ScriptlistChangedExecute); }
        }

        private void ScriptlistChangedExecute()
        {
            ScriptName = SelectedScript;
        }

        #endregion

        #region Delete Script Command
        /// <summary>
        /// Runs DeleteScriptExecute() when the delete script image is pressed.
        /// </summary>
        public ICommand DeleteScript_Cmd
        {
            get { return new RelayCommand(DeleteScriptExecute); }
        }

        /// <summary>
        /// Deletes the selected script from the database in a backgroundworker.
        /// </summary>
        private void DeleteScriptExecute()
        {
            bgw = new BackgroundWorker();
            bgw.DoWork += Bgw_DeleteScript_DoWork;
            bgw.RunWorkerCompleted += Bgw_DeleteScript_Complete;

            bgw.RunWorkerAsync();
        }
        #endregion

        #region Load Script Command
        /// <summary>
        /// 
        /// </summary>
        private void LoadScriptExecute()
        {
            bgw = new BackgroundWorker();
            bgw.DoWork += Bgw_LoadScript_DoWork;
            bgw.RunWorkerCompleted += Bgw_LoadScript_Complete;
        
            bgw.RunWorkerAsync();
        }
        #endregion
        #region Save Script Command
        /// <summary>
        /// Runs SaveScriptExecute() when Save button is pressed.
        /// </summary>
        public ICommand SaveScript_Cmd
        {
            get { return new RelayCommand(SaveScriptExecute); }
        }

        /// <summary>
        /// Saves or overwrites the script in the database in a background worker.
        /// </summary>
        private void SaveScriptExecute()
        {
            bgw = new BackgroundWorker();
            bgw.DoWork += Bgw_SaveScript_DoWork;
            bgw.RunWorkerCompleted += Bgw_SaveScript_Complete;

            bgw.RunWorkerAsync();
        }
        #endregion
        #region Debug Script Command
        public ICommand DebugScript_Cmd
        {
            get { return new RelayCommand(DebugScriptExecute); }
        }

        /// <summary>
        /// Debugs the script to find syntax errors and variable declaration and usage errors
        /// </summary>
        private void DebugScriptExecute()
        {
            Compiler compiler = new Compiler();
            List<String> errorList = new List<string>();

            ProcessManagement.ProcessManagement pm = new ProcessManagement.ProcessManagement(false);

            var v = compiler.Compile(CodeLines);
            errorList = compiler.GetErrorList();
            pm.RobotConnected = false;

            DebugMessages.Clear();
            try
            {
                if (errorList.Count == 0)
                {
                    variableExceptionThrown = false;
                    pm.DFSRecursiveRunThroughOfASTForDebug(v);
                }
            }
            catch (ProcessManagement.ProcessManagement.variableException e)
            {
                DebugMessages.Add(e.Message);
                variableExceptionThrown = true;

            }
            
            
            if(errorList.Count == 0 && !variableExceptionThrown)
            {
                StatusEllipseColor = new SolidColorBrush(Colors.Green);
                DebugMessages.Add("No errors!");
            }
            else
            {
                StatusEllipseColor = new SolidColorBrush(Colors.Red);
                
                foreach (var VARIABLE in errorList)
                {
                    DebugMessages.Add(VARIABLE);
                    
                }
            }
        }
        #endregion
        #region Execute Script Command
        public ICommand ExecuteScript_Cmd
        {
            get { return new RelayCommand(ExecuteScriptExecute); }
        }

        /// <summary>
        /// Debugs the script and makes the script executable
        /// </summary>
        private void ExecuteScriptExecute()
        {
            Compiler compiler = new Compiler();
            List<String> errorList = new List<string>();
            ProcessManagement.ProcessManagement pm = new ProcessManagement.ProcessManagement(false);

            var v = compiler.Compile(CodeLines);
            
            errorList = compiler.GetErrorList();
            DebugMessages.Clear();
            try
            {
                if (errorList.Count == 0)
                {
                    variableExceptionThrown = false;
                    pm.DFSRecursiveRunThroughOfASTForDebug(v);
                }
                
            }
            catch (ProcessManagement.ProcessManagement.variableException e)
            {
                DebugMessages.Add(e.Message);
                variableExceptionThrown = true;

            }

            if (errorList.Count == 0 && !variableExceptionThrown)
            {
                StatusEllipseColor = new SolidColorBrush(Colors.Green);
                DebugMessages.Add("Script compiled without errors.");
                DebugMessages.Add("Ready to start script in opperator tab!");

                MessengerInstance.Send(v);
            }
            else
            {
                StatusEllipseColor = new SolidColorBrush(Colors.Red);
                
                foreach (var VARIABLE in errorList)
                {
                    DebugMessages.Add(VARIABLE);

                }
            }

        }
        #endregion
        #endregion
        #region Background Worker
        #region GetScript BGW
        private void Bgw_GetScriptList_DoWork(object sender, DoWorkEventArgs e)
        {
            List<String> tempList = new List<String>();
            tempList = db.ReadScriptNames();

            e.Result = tempList;
        }
        private void Bgw_GetScriptList_Complete(object sender, RunWorkerCompletedEventArgs e)
        {
            ScriptList.Clear();
            foreach (var script in (List<String>)e.Result)
            {
                ScriptList.Add(script);
            }
        }
        #endregion
        #region Load Script BGW
        private void Bgw_LoadScript_DoWork(object sender, DoWorkEventArgs e)
        {
            Script scriptList = db.ReadScript(SelectedScript);
            e.Result = scriptList;
        }
        private void Bgw_LoadScript_Complete(object sender, RunWorkerCompletedEventArgs e)
        {
            Script returnedScript = (Script)e.Result;
            CodeLines = returnedScript.CodeLines;
        }
        #endregion
        #region Save Script BGW
        private void Bgw_SaveScript_DoWork(object sender, DoWorkEventArgs e)
        {
            db.WriteScript(new Script(ScriptName, CodeLines));
        }
        private void Bgw_SaveScript_Complete(object sender, RunWorkerCompletedEventArgs e)
        {
            RefreshScriptListExecute();
        }
        #endregion
        #region Delete Script BGW
        private void Bgw_DeleteScript_DoWork(object sender, DoWorkEventArgs e)
        {
            db.RemoveScript(SelectedScript);
        }
        private void Bgw_DeleteScript_Complete(object sender, RunWorkerCompletedEventArgs e)
        {
            RefreshScriptListExecute();
        }
        #endregion
        #endregion

    }
}
